//
//  MyManagedObjectContext.m
//  My Dream Slapper
//
//  Created by Jason Harris on 8/24/06.
//  Copyright (c) 2006, Jason Harris and Geekspiff
//  All rights reserved.
//  
//  Redistribution and use in source and binary forms, with or without modification, are permitted provided
//  that the following conditions are met:
//  
//  Redistributions of source code must retain the above copyright notice, this list of conditions and the
//  following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list
//  of conditions and the following disclaimer in the documentation and/or other materials provided with the
//  distribution. Neither the name of Jason Harris, Geekspiff, nor the names of its contributors may be used
//  to endorse or promote products derived from this software without specific prior written permission.
//  
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
//  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
//  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
//  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//  POSSIBILITY OF SUCH DAMAGE.
//

#import "MyManagedObjectContext.h"
#import "ContestEntry.h"


@implementation MyManagedObjectContext

#pragma mark Creation and Destruction

- (void)dealloc
{
	[self uncacheSQLUser];
	[_folders release];
	[super dealloc];
}


- (void)insertObject: (NSManagedObject *)object
{
	[super insertObject: object];
	if ([object isKindOfClass: [ContestEntry class]])
		[self categorizeContestEntry: object];
}


- (void)deleteObject: (NSManagedObject *)object
{
	if ([object isKindOfClass: [ContestEntry class]])
		[self categorizeContestEntry: object];
	[super deleteObject: object];
}


#pragma mark Object State


- (NSArray *)dirtyObjects
{
	NSError *error;
	NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
	NSEntityDescription *entity = [NSEntityDescription entityForName: @"DirtyObject" inManagedObjectContext: self];
	[fetchRequest setEntity: entity];
	NSArray *foundObjects = [self executeFetchRequest: fetchRequest error: &error];
	if ( !foundObjects && error )
		[NSException raise: NSGenericException format: @"%@", error];
	return foundObjects;
}


- (void)markObjectAsDirty: (NSManagedObject *)object
{
	NSString *uuid = [object valueForKey: @"uuid"];

	NSError *error;
	NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
	NSEntityDescription *entity = [NSEntityDescription entityForName: @"DirtyObject" inManagedObjectContext: self];
	[fetchRequest setEntity: entity];

	NSPredicate *predicate = [NSPredicate predicateWithFormat: @"uuid == %@", uuid];
	[fetchRequest setPredicate: predicate];
	NSArray *foundObjects = [self executeFetchRequest: fetchRequest error: &error];
	if ( ! foundObjects && error )
		[NSException raise: NSGenericException format: @"%@", error];
	if ( 1 == [foundObjects count] ) return;

	id dirtyObject = [NSEntityDescription insertNewObjectForEntityForName: @"DirtyObject" inManagedObjectContext: self];
	[dirtyObject setValue: uuid forKey: @"uuid"];
	[dirtyObject setValue: [[object entity] managedObjectClassName] forKey: @"nameOfClass"];
}


#pragma mark MySQL User Management


- (NSManagedObject *)sqlUserForSQLUserID: (NSNumber *)userID
{
	NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
	NSEntityDescription *entity = [NSEntityDescription entityForName: @"SQLUser" inManagedObjectContext: self];
	[fetchRequest setEntity: entity];
	
	NSError *error;
	NSPredicate *predicate = [NSPredicate predicateWithFormat: @"id == %@", userID];
	[fetchRequest setPredicate: predicate];
	NSArray *foundEntries = [self executeFetchRequest: fetchRequest error: &error];
	if ( foundEntries )
	{
		unsigned int count = [foundEntries count];
		if ( count > 0 )
		{
			if ( count != 1 )
				[NSException raise: NSGenericException format: @"a duplicate userID (%@) was found", userID];
			return [foundEntries lastObject];
		}
	}
	return nil;
}


- (NSManagedObject *)sqlUserForSQLUsername: (NSString *)username
{
	NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
	NSEntityDescription *entity = [NSEntityDescription entityForName: @"SQLUser" inManagedObjectContext: self];
	[fetchRequest setEntity: entity];
	
	NSError *error;
	NSPredicate *predicate = [NSPredicate predicateWithFormat: @"sqlUsername == %@", username];
	[fetchRequest setPredicate: predicate];
	NSArray *foundEntries = [self executeFetchRequest: fetchRequest error: &error];
	if ( foundEntries )
	{
		unsigned int count = [foundEntries count];
		if ( count > 0 )
		{
			if ( count != 1 )
				[NSException raise: NSGenericException format: @"a duplicate username (%@) was found", username];
			return [foundEntries lastObject];
		}
	}
	return nil;
}


- (NSManagedObject *)mySQLUser
{
	if ( _mySQLUser ) return _mySQLUser;
	
	NSString *username = [[[NSUserDefaultsController sharedUserDefaultsController] values] valueForKey: @"LastValidSQLUsername"];
	NSParameterAssert( username != nil );
	
	NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
	NSEntityDescription *entity = [NSEntityDescription entityForName: @"SQLUser" inManagedObjectContext: self];
	[fetchRequest setEntity: entity];
	
	NSError *error;
	NSPredicate *predicate = [NSPredicate predicateWithFormat: @"sqlUsername == %@", username];
	[fetchRequest setPredicate: predicate];
	NSArray *foundEntries = [self executeFetchRequest: fetchRequest error: &error];
	if ( !foundEntries && error )
		[NSException raise: NSGenericException format: @"%@", error];
	
	unsigned int count = [foundEntries count];
	if ( count > 0 )
	{
		if ( count != 1 )
			[NSException raise: NSGenericException format: @"a duplicate username (%@) was found", username];
		_mySQLUser = [foundEntries lastObject];
		return _mySQLUser;
	}
	
	[NSException raise: NSGenericException format: @"unable to determine MySQL userid"];
	return nil;
}


- (void)uncacheSQLUser
{  _mySQLUser = nil;  }


#pragma mark Miscellaneous


- (NSArray *)folders
{
	if (!_folders)
	{
		NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
		NSEntityDescription *entity = [NSEntityDescription entityForName: @"Folder" inManagedObjectContext: self];
		[fetchRequest setEntity: entity];
		
		NSError *error;
		_folders = [[self executeFetchRequest: fetchRequest error: &error] retain];
		if ( !_folders && error )
			[NSException raise: NSGenericException format: @"%@", error];
	}
	return _folders;
}


- (void)categorizeContestEntry: (NSManagedObject *)contestEntry
{
	NSArray *folders = [self folders];
	unsigned i, count = [folders count];
	for (i = 0; i < count; ++i)
	{
		NSManagedObject *folder = [folders objectAtIndex: i];
		NSMutableSet *entries = [folder mutableSetValueForKey: @"entries"];
		NSPredicate *predicate = [folder valueForKey: @"predicate"];
		if ([predicate evaluateWithObject: contestEntry])
			[entries addObject: contestEntry];
		else
			[entries removeObject: contestEntry];
	}
}


- (NSManagedObject *)contestEntryWithID: (NSNumber *)submissionID
{
	NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
	NSEntityDescription *contestEntity = [NSEntityDescription entityForName: @"ContestEntry" inManagedObjectContext: self];
	[fetchRequest setEntity: contestEntity];
	
	NSError *error;
	NSPredicate *predicate = [NSPredicate predicateWithFormat: @"id == %@", submissionID];
	[fetchRequest setPredicate: predicate];
	NSArray *foundEntries = [self executeFetchRequest: fetchRequest error: &error];
	if (!foundEntries && error)
		[NSException raise: NSGenericException format: @"%@", error];
	if ([foundEntries count] == 1)
		return [foundEntries lastObject];
	
	NSLog(@"There was an attempt to locate a contest entry based on an invalid ID.  The invalid contest entry ID is %@", submissionID);
	return nil;
}

@end
